home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / addr_util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-31  |  11.9 KB  |  449 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: addr_util.c,v 5.10 1993/05/31 19:32:20 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.10 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1988-1992 USENET Community Trust
  8.  *             Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: addr_util.c,v $
  17.  * Revision 5.10  1993/05/31  19:32:20  syd
  18.  * With this patch build_address() should treat local mailing
  19.  * lists and other aliases known by the transport agent as valid
  20.  * addresses.
  21.  * I also conditionalized printing the "Expands to: " message
  22.  * in check_only mode to be done only when there is an expanded
  23.  * address to print. Build_address will inform anyway about an
  24.  * alias that does not exist.
  25.  * From: Jukka Ukkonen <ukkonen@csc.fi>
  26.  *
  27.  * Revision 5.9  1993/05/14  03:53:46  syd
  28.  * Fix wrong message being displayed and then overwritten
  29.  * for long aliases.
  30.  * From: "Robert L. Howard" <robert.howard@matd.gatech.edu>
  31.  *
  32.  * Revision 5.8  1993/04/16  03:26:50  syd
  33.  * For many embedded X.400 addresses in the format
  34.  * "/.../.../.../.../"@admd.country NLEN was simply too short and part of
  35.  * the address never made it to the reply address. In my opinion 512 bytes
  36.  * should be enough. So make it LONG_STRING.
  37.  * From: Jukka Ukkonen <ukkonen@csc.fi>
  38.  *
  39.  * Revision 5.7  1993/01/19  05:07:05  syd
  40.  * Trim erroreous extra log entry
  41.  * From: Syd
  42.  *
  43.  * Revision 5.6  1993/01/19  04:47:12  syd
  44.  * Significant changes to provide consistent Date and From_ header
  45.  * cracking.  Overhauled date utilities and moved into library.  Moved
  46.  * real_from() into library.  Modified frm, newmail, and readmsg utilities
  47.  * to use library version of real_from().  Moved get_word() from Elm
  48.  * source into library.  Added new library routines atonum() and strfcpy().
  49.  * Fixed trailing backslash bug in len_next().
  50.  * From: chip@chinacat.unicom.com (Chip Rosenthal)
  51.  *
  52.  * Revision 5.5  1992/12/11  01:45:04  syd
  53.  * remove sys/types.h include, it is now included by defs.h
  54.  * and this routine includes defs.h or indirectly includes defs.h
  55.  * From: Syd
  56.  *
  57.  * Revision 5.4  1992/11/26  00:46:13  syd
  58.  * changes to first change screen back (Raw off) and then issue final
  59.  * error message.
  60.  * From: Syd
  61.  *
  62.  * Revision 5.3  1992/10/31  18:52:51  syd
  63.  * Corrections to Unix date parsing and time zone storage
  64.  * From: eotto@hvlpa.att.com
  65.  *
  66.  * Revision 5.2  1992/10/25  02:18:01  syd
  67.  * fix found_year flag
  68.  * From: Syd
  69.  *
  70.  * Revision 5.1  1992/10/03  22:58:40  syd
  71.  * Initial checkin as of 2.4 Release at PL0
  72.  *
  73.  *
  74.  ******************************************************************************/
  75.  
  76. /** This file contains addressing utilities 
  77.  
  78. **/
  79.  
  80. #include "headers.h"
  81. #include "s_elm.h"
  82.  
  83. #include <ctype.h>
  84.  
  85. #ifdef BSD 
  86. #undef tolower
  87. #undef toupper
  88. #endif
  89.  
  90.  
  91. translate_return(addr, ret_addr)
  92. char *addr, *ret_addr;
  93. {
  94.     /** Return ret_addr to be the same as addr, but with the login 
  95.             of the person sending the message replaced by '%s' for 
  96.             future processing... 
  97.         Fixed to make "%xx" "%%xx" (dumb 'C' system!) 
  98.     **/
  99.  
  100.     register int loc, loc2, iindex = 0;
  101.     register char *remaining_addr;
  102.     
  103. /*
  104.  *    check for RFC-822 source route: format @site:usr@site
  105.  *    if found, skip to after the first : and then retry.
  106.  *    source routes can be stacked
  107.  */
  108.     remaining_addr = addr;
  109.     while (*remaining_addr == '@') {
  110.       loc = qchloc(remaining_addr, ':');
  111.       if (loc == -1)
  112.         break;
  113.  
  114.       remaining_addr += loc + 1;
  115.     }
  116.  
  117.     loc2 = qchloc(remaining_addr,'@');
  118.     loc = qchloc(remaining_addr, '%');
  119.     if ((loc < loc2) && (loc != -1))
  120.       loc2 = loc;
  121.  
  122.     if (loc2 != -1) {    /* ARPA address. */
  123.       /* algorithm is to get to '@' sign and move backwards until
  124.          we've hit the beginning of the word or another metachar.
  125.       */
  126.       for (loc = loc2 - 1; loc > -1 && remaining_addr[loc] != '!'; loc--)
  127.          ;
  128.     }
  129.     else {            /* usenet address */
  130.       /* simple algorithm - find last '!' */
  131.  
  132.       loc2 = strlen(remaining_addr);    /* need it anyway! */
  133.  
  134.       for (loc = loc2; loc > -1 && remaining_addr[loc] != '!'; loc--)
  135.           ;
  136.     }
  137.     
  138.     /** now copy up to 'loc' into destination... **/
  139.  
  140.     while (iindex <= loc) {
  141.       ret_addr[iindex] = remaining_addr[iindex];
  142.       iindex++;
  143.     }
  144.  
  145.     /** now append the '%s'... **/
  146.  
  147.     ret_addr[iindex++] = '%';
  148.     ret_addr[iindex++] = 's';
  149.  
  150.     /*
  151.      *  and, finally, if anything left, add that
  152.      * however, just pick up the address part, we do
  153.      * not want any comments.  Thus stop copying at
  154.      * the first blank character.
  155.      */
  156.  
  157.     if ((loc = qchloc(remaining_addr,' ')) == -1)
  158.       loc = strlen(addr);
  159.     while (loc2 < loc) {
  160.       ret_addr[iindex++] = remaining_addr[loc2++];
  161.       if (remaining_addr[loc2-1] == '%')    /* tweak for "printf" */
  162.         ret_addr[iindex++] = '%';
  163.     }
  164.     
  165.     ret_addr[iindex] = '\0';
  166. }
  167.  
  168. int
  169. build_address(to, full_to)
  170. char *to, *full_to;
  171. {
  172.     /** loop on all words in 'to' line...append to full_to as
  173.         we go along, until done or length > len.  Modified to
  174.         know that stuff in parens are comments...Returns non-zero
  175.         if it changed the information as it copied it across...
  176.     **/
  177.  
  178.     register int    i, j, k, l,
  179.             changed = 0, in_parens = 0,
  180.             expanded_information = 0,
  181.             eliminated = 0;
  182.     int too_long = FALSE;
  183.     char word[SLEN], next_word[SLEN], *ptr, buffer[SLEN];
  184.     char new_to_list[VERY_LONG_STRING];
  185.     char elim_list[SLEN], word_a[SLEN], next_word_a[SLEN];
  186.     char *qstrpbrk(), *gecos;
  187.     extern char *get_full_name(), *get_alias_address();
  188.  
  189.     new_to_list[0] = '\0';
  190.  
  191.     i = get_word(to, 0, word, sizeof(word));
  192.  
  193.     full_to[0] = '\0';
  194.  
  195.     elim_list[0] = '\0';
  196.  
  197.     /** Look for addresses to be eliminated from aliases **/
  198.     while (i > 0) {
  199.  
  200.       j = get_word(to, i, next_word, sizeof(next_word));
  201.  
  202.       if(word[0] == '(')
  203.         in_parens++;
  204.  
  205.       if (in_parens) {
  206.         if(word[strlen(word)-1] == ')')
  207.           in_parens--;
  208.       }
  209.  
  210.       else if (word[0] == '-'){
  211.         for (k=0; word[k]; word[k] = word[k+1],k++);
  212.         if (elim_list[0] != '\0')
  213.           strcat(elim_list, " ");
  214.         strcat(elim_list, word);
  215.       }
  216.       if ((i = j) > 0)
  217.         strcpy(word, next_word);
  218.     }
  219.  
  220.     if (elim_list[0] != '\0')
  221.       eliminated++;
  222.  
  223.     i = get_word(to, 0, word, sizeof(word));
  224.  
  225.     while (i > 0) {
  226.  
  227.       j = get_word(to, i, next_word, sizeof(next_word));
  228.  
  229. try_new_word:
  230.       if(word[0] == '(')
  231.         in_parens++;
  232.  
  233.       if (in_parens) {
  234.         if(word[strlen(word)-1] == ')')
  235.           in_parens--;
  236.         strcat(full_to, " ");
  237.         strcat(full_to, word);
  238.       }
  239.  
  240.       else if (word[0] == '-') {
  241.       }
  242.  
  243.       else if (qstrpbrk(word,"!@:") != NULL) {
  244.         sprintf(full_to, "%s%s%s", full_to,
  245.                     full_to[0] != '\0'? ", " : "", word);
  246.       }
  247.       else if ((ptr = get_alias_address(word, TRUE, &too_long)) != NULL) {
  248.  
  249.         /** check aliases for addresses to be eliminated **/
  250.         if (eliminated) {
  251.           k = get_word(strip_commas(ptr), 0, word_a, sizeof(word_a));
  252.  
  253.           while (k > 0) {
  254.         l = get_word(ptr, k, next_word_a, sizeof(next_word_a));
  255.         if (in_list(elim_list, word_a) == 0)
  256.           sprintf(full_to, "%s%s%s", full_to,
  257.               full_to[0] != '\0' ? ", " : "", word_a);
  258.         if ((k = l) > 0)
  259.           strcpy(word_a, next_word_a);
  260.           }
  261.         } else
  262.           sprintf(full_to, "%s%s%s", full_to, 
  263.                       full_to[0] != '\0'? ", " : "", ptr);
  264.         expanded_information++;
  265.       }
  266.       else if (too_long) {
  267.      /*
  268.       *   We don't do any real work here.  But we need some
  269.       *   sort of test in this line of tests to make sure
  270.       *   that none of the other else's are tried if the 
  271.       *   alias expansion failed because it was too long.
  272.       */
  273.           dprint(2,(debugfile,"Overflowed alias expansion for %s\n", word));
  274.       }
  275.       else if (strlen(word) > 0) {
  276.         if (valid_name(word)) {
  277.           if (j > 0 && next_word[0] == '(')    /* already has full name */
  278.         gecos = NULL;
  279.           else                /* needs a full name */
  280.         gecos = get_full_name(word);
  281. #if defined(INTERNET) & defined(USE_DOMAIN)
  282.           sprintf(full_to, "%s%s%s@%s%s%s%s",
  283.               full_to,
  284.               (full_to[0] ? ", " : ""),
  285.               word,
  286.               hostfullname,
  287.               (gecos ? " (" : ""),
  288.               (gecos ? gecos : ""),
  289.               (gecos ? ")" : ""));
  290. #else /* INTERNET and USE_DOMAIN */
  291.           sprintf(full_to, "%s%s%s%s%s%s",
  292.               full_to,
  293.               (full_to[0] ? ", " : ""),
  294.               word,
  295.               (gecos ? " (" : ""),
  296.               (gecos ? gecos : ""),
  297.               (gecos ? ")" : ""));
  298. #endif /* INTERNET and USE_DOMAIN */
  299.         }
  300.         else if (check_only) {
  301.         if (! isatty(fileno(stdin)) ) {
  302.             /*
  303.              *    batch mode error!
  304.              */
  305.             Raw(OFF);
  306.             fprintf(stderr,
  307.                 catgets(elm_msg_cat, ElmSet, ElmCannotExpandNoCR,
  308.                     "Cannot expand alias '%s'!\n"),
  309.                 word);
  310.             fprintf(stderr,
  311.                 catgets(elm_msg_cat, ElmSet, ElmUseCheckalias,
  312.                     "Use \"checkalias\" to find valid addresses!\n"));
  313.             dprint(1, (debugfile,
  314.                    "Can't expand alias %s - bailing out of build_address\n", 
  315.                    word));
  316.             leave(0);
  317.         }
  318.         else {
  319.             printf(catgets(elm_msg_cat, ElmSet, ElmAliasUnknown,
  320.             "(alias \"%s\" is unknown)\n\r"), word);
  321.             changed++;
  322.         }
  323.         }
  324.         else {
  325.           sprintf(full_to, "%s%s%s",
  326.               full_to,
  327.               (full_to[0] ? ", " : ""),
  328.               word);
  329.         }
  330.       }
  331.  
  332.       /* and this word to the new to list */
  333.       if(*new_to_list != '\0')
  334.         strcat(new_to_list, " ");
  335.       strcat(new_to_list, word);
  336.  
  337.       if((i = j) > 0)
  338.         strcpy(word, next_word);
  339.     }
  340.  
  341.     /* if new to list is different from original, update original */
  342.     if (changed)
  343.       strcpy(to, new_to_list);
  344.  
  345.     return( expanded_information > 0 ? 1 : 0 );
  346. }
  347.  
  348.  
  349. forwarded(buffer, entry)
  350. char *buffer;
  351. struct header_rec *entry;
  352. {
  353.     /** Change 'from' and date fields to reflect the ORIGINATOR of 
  354.         the message by iteratively parsing the >From fields... 
  355.         Modified to deal with headers that include the time zone
  356.         of the originating machine... **/
  357.  
  358.     char machine[SLEN], buff[SLEN], holding_from[SLEN];
  359.     int len;
  360.  
  361.     machine[0] = holding_from[0] = '\0';
  362.  
  363.     sscanf(buffer, "%*s %s", holding_from);
  364.  
  365.     /* after skipping over From and address, process rest as date field */
  366.  
  367.     while (!isspace(*buffer)) buffer++;    /* skip From */
  368.     while (isspace(*buffer)) buffer++;
  369.  
  370.     while (*buffer) {
  371.       len = len_next_part(buffer);
  372.       if (len > 1) {
  373.         buffer += len;
  374.       } else {
  375.         if (isspace(*buffer))
  376.           break;
  377.         buffer++;
  378.       }
  379.     }
  380.     while (isspace(*buffer)) buffer++;
  381.  
  382.     parse_arpa_date(buffer, entry);
  383.  
  384.     /* the following fix is to deal with ">From xyz ... forwarded by xyz"
  385.        which occasionally shows up within AT&T.  Thanks to Bill Carpenter
  386.        for the fix! */
  387.  
  388.     if (strcmp(machine, holding_from) == 0)
  389.       machine[0] = '\0';
  390.  
  391.     if (machine[0] == '\0')
  392.       strcpy(buff, holding_from[0] ? holding_from : "anonymous");
  393.     else
  394.       sprintf(buff,"%s!%s", machine, holding_from);
  395.  
  396.     strfcpy(entry->from, buff, STRING);
  397. }
  398.  
  399.  
  400. fix_arpa_address(address)
  401. char *address;
  402. {
  403.     /** Given a pure ARPA address, try to make it reasonable.
  404.  
  405.         This means that if you have something of the form a@b@b make 
  406.             it a@b.  If you have something like a%b%c%b@x make it a%b@x...
  407.     **/
  408.  
  409.     register int host_count = 0, i;
  410.     char     hosts[MAX_HOPS][LONG_STRING];    /* array of machine names */
  411.     char     *host, *addrptr;
  412.     extern char *get_token();
  413.  
  414.     /*  break down into a list of machine names, checking as we go along */
  415.     
  416.     addrptr = (char *) address;
  417.  
  418.     while ((host = get_token(addrptr, "%@", 2)) != NULL) {
  419.       for (i = 0; i < host_count && ! equal(hosts[i], host); i++)
  420.           ;
  421.  
  422.       if (i == host_count) {
  423.         strcpy(hosts[host_count++], host);
  424.         if (host_count == MAX_HOPS) {
  425.            dprint(2, (debugfile, 
  426.            "Can't build return address - hit MAX_HOPS in fix_arpa_address\n"));
  427.            error(catgets(elm_msg_cat, ElmSet, ElmCantBuildRetAddr,
  428.             "Can't build return address - hit MAX_HOPS limit!"));
  429.            return(1);
  430.         }
  431.       }
  432.       else 
  433.         host_count = i + 1;
  434.       addrptr = NULL;
  435.     }
  436.  
  437.     /** rebuild the address.. **/
  438.  
  439.     address[0] = '\0';
  440.  
  441.     for (i = 0; i < host_count; i++)
  442.       sprintf(address, "%s%s%s", address, 
  443.               address[0] == '\0'? "" : 
  444.              (i == host_count - 1 ? "@" : "%"),
  445.               hosts[i]);
  446.  
  447.     return(0);
  448. }
  449.